package com.wtf.dsp.admin.core.provider;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.mybatisplus.annotation.DbType;
import com.wtf.dsp.admin.annotation.DbTypeFlag;
import com.wtf.dsp.admin.annotation.SqlExec;
import com.wtf.dsp.admin.core.executor.AbstractExecutor;
import com.wtf.dsp.admin.core.model.DataSourceInfo;
import com.wtf.dsp.admin.core.dao.AbstractJdbcDao;
import com.wtf.dsp.admin.enums.CommonErrorEnum;
import com.wtf.dsp.admin.exception.WtfDspException;
import com.wtf.dsp.admin.model.dto.DsSqlDTO;
import com.wtf.dsp.core.constant.NsConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.annotation.AnnotationUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * ClassName: AbstractDynamicDataSourceProvider
 * Description:
 * date: 2024/3/7 18:05
 *
 * @author linhuanyou
 * @version 1.0
 */
@Slf4j
public abstract class AbstractWtfDynamicDataSourceProvider extends AbstractExecutor implements WtfDynamicDataSourceProvider, InitializingBean {

    private DynamicDataSourceConfigProvide dynamicDataSourceConfigProvide;

    private AbstractJdbcDao databaseDao;

    public AbstractWtfDynamicDataSourceProvider(DynamicDataSourceConfigProvide dynamicDataSourceConfigProvide, AbstractJdbcDao databaseDao) {
        this.dynamicDataSourceConfigProvide = dynamicDataSourceConfigProvide;
        this.databaseDao = databaseDao;
    }

    @Override
    protected void initExecutors() {
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    }

    public DataSourceProperty getDataSourceProperty(DataSourceInfo dataSourceInfo){
        return this.databaseDao.getDataSourceProperty(dataSourceInfo);
    }

    public boolean testConnectDb(DataSourceInfo dataSourceInfo) throws Exception{
        if(this.databaseDao == null){
            return false;
        }
        Connection connection = null;
        try {
            connection = this.databaseDao.openConnection(dataSourceInfo);
            return true;
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                this.databaseDao.closeConnection(connection);
            } catch (WtfDspException e) {

            }
        }
    }

    @Override
    public void addDataSources(DataSourceInfo dataSourceInfo) {
        DataSourceProperty dataSourceProperty = getDataSourceProperty(dataSourceInfo);
        DataSource dataSource = dynamicDataSourceConfigProvide.getDefaultDataSourceCreator().createDataSource(dataSourceProperty);
        DynamicRoutingDataSource dynamicRoutingDataSource = dynamicDataSourceConfigProvide.getDynamicRoutingDataSource();
        dynamicRoutingDataSource.addDataSource(dataSourceProperty.getPoolName(),dataSource);
    }

    @Override
    public void removeDataSource(String ns, String ds) {
        DynamicRoutingDataSource dynamicRoutingDataSource = dynamicDataSourceConfigProvide.getDynamicRoutingDataSource();
        dynamicRoutingDataSource.removeDataSource(NsConstant.nsGroupDs(ns,ds));
        log.info("Remove Dynamic Data Source Ns : {} Ds : {}",ns,ds);
    }

    @Override
    public List<DataSourceInfo> loadDataSources() {
        return getDataSources();
    }

    public abstract List<DataSourceInfo> getDataSources();

    public abstract DataSourceInfo getDataSource(String ns, String ds);

    @SqlExec
    public <T> T doExecutor(DsSqlDTO dsSqlDTO, TypeReference<T> clazz) throws Exception {
        String excSql = dsSqlDTO.getExcSql();
        Object result = null;
        switch (dsSqlDTO.getSqlType()){
            case DELETE:
            case UPDATE:
            case INSERT:
                result = this.databaseDao.insertDeleteUpdate(excSql);
                return (T)result;
            default:
                switch (dsSqlDTO.getSqlResponseMapper()){
                    case MAP_LIST:
                        result = this.databaseDao.queryForList(excSql);
                        break;
                    case MAP:
                        result = this.databaseDao.queryForMap(excSql);
                        break;
                    case PAGE:
                        result = this.databaseDao.queryForPage(dsSqlDTO.getPageSql());
                        break;
                    case T:
                        Class<?> tClass = Class.forName(clazz.getType().getTypeName());
                        result = this.databaseDao.queryForObject(excSql,tClass);
                        break;
                    case T_LIST:
                        Class<?> tListClass = Class.forName(clazz.getType().getTypeName());
                        result = this.databaseDao.queryForList(excSql,tListClass);
                        break;
                    default:
                        throw new WtfDspException(CommonErrorEnum.ERROR_VALID);
                }
                return JSONObject.parseObject(JSON.toJSONString(result),clazz);
        }
    }

    public Boolean testDriver(String driverClass) {
        return databaseDao.checkDriver(driverClass);
    }
}
